﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using OpenLS.Spreadsheet.Expressions;

namespace OpenLS.Spreadsheet.Formats.Biff.Records
{
    internal class CFGradient : CFBase
    {
        private bool fBackground;
        private bool fClamp;
        private byte reserved1;
        private readonly  List<CFGradientItem> rgCurve = new List<CFGradientItem>();
        private readonly List<CFGradientInterpItem> rgInterp = new List<CFGradientInterpItem>();
        private ushort unused = 133;

        public CFGradient(ColorScale colorScale)
        {
            this.fClamp = true;
            fBackground = true;
            double count = colorScale.Colors.Count;
            if (count > 0)
                count--;
            for (int i = 0; i < colorScale.Colors.Count; i++)
            {
                rgCurve.Add(new CFGradientItem(colorScale.Colors[i], (i + 0) / (count)));
            }
            count = colorScale.Conditions.Count;
            if (count > 0)
                count--;
            for (int i = 0; i < colorScale.Conditions.Count; i++)
            {
                this.rgInterp.Add(new CFGradientInterpItem(colorScale.Conditions[i], (i + 0) / (count)));
            }
        }

        public CFGradient()
        {
        }

        protected byte Ab
        {
            get
            {
                byte result = 0;
                if (fClamp)
                    result |= 1;
                if (fBackground)
                    result |= 2;
                return result;
            }
        }

        public override void Read(BinaryReader reader)
        {
#if DEBUG
            ReadWriteChecker.CheckClass((t, r) => t.Read(r), (t, w) =>t.Write(w), reader, this);
            var position = reader.BaseStream.Position;
#endif
            unused = reader.ReadUInt16();
            reserved1 = reader.ReadByte();
            byte cInterpCurve = reader.ReadByte();
            byte cGradientCurve = reader.ReadByte();
            byte ab = reader.ReadByte();
            fClamp = (ab & 0x01) != 0;
            fBackground = (ab & 0x02) != 0;
            Contract.Assert(Ab == ab);
            rgInterp.Clear();
            for (int i = 0; i < cInterpCurve; i++)
            {
                var item = new CFGradientInterpItem();
                item.Read(reader);
                rgInterp.Add(item);
            }
            rgCurve.Clear();
            for (int i = 0; i < cGradientCurve; i++)
            {
                var item = new CFGradientItem();
                item.Read(reader);
                rgCurve.Add(item);
            }
        }

        public override void Write(BinaryWriter writer)
        {
            writer.Write(unused);
            writer.Write(reserved1);
            var cInterpCurve = (byte) rgInterp.Count;
            var cGradientCurve = (byte) rgCurve.Count;
            writer.Write(cInterpCurve);
            writer.Write(cGradientCurve);
            writer.Write(Ab);
            foreach (CFGradientInterpItem item in rgInterp)
                item.Write(writer);
            foreach (CFGradientItem item in rgCurve)
                item.Write(writer);
        }

        public ColorScale ToColorScale(BiffReaderWorksheetContext context)
        {
            var result = new ColorScale();
            foreach (CFGradientItem item in rgCurve)
            {
                result.Colors.Add(item.ToColor());
            }
            foreach (var item in rgInterp)
            {
                result.Conditions.Add(item.ToCondition(context));
            }

            return result;
        }
    }
}